//! $Id: BindContext.h 27 2011-09-16 13:28:08Z skagget77 $
//!
//! @file    BindContext.h
//! @author  Johan Andersson <skagget77@gmail.com>
//! @date    Thu Oct 01 20:03 2009
//! @ingroup IoCpp
//!

#if !defined(IOCPP_CONFIG_BINDCONTEXT_H)
#define IOCPP_CONFIG_BINDCONTEXT_H

#include "IoCpp/IContainer.h"

#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include <string>

namespace IoCpp
{
   //!
   //! Proxy to represent a provider as a singleton object.
   //!
   //! @param  provider The provider.
   //!
   //! @return The singleton object.
   //!
   template<class T1>
   T1 SingletonProxy( boost::function<T1 ()> provider  ) 
   {
      static T1 singleton = provider();
      return singleton;
   }

   //!
   //! @author  Johan Andersson <skagget77@gmail.com>
   //! @date    Thu Oct 01 20:03 2009
   //! @ingroup IoCpp
   //!
   //! The BindContext class, holds the state of the fluent interface while
   //! binding a type to a provider.
   //!
   template<class T1>
   class BindContext 
   {
   public :
      //!
      //! Creates a new instance of the BindContext class.
      //!
      //! @param container The container.
      //!
      BindContext( IContainerPtr container )
         : mContainer(container) {
      }

      //!
      //! Returns the container.
      //!
      //! @return The container.
      //!
      IContainerPtr GetContainer() const {
         return mContainer;
      }

      //!
      //! Sets the provider.
      //!
      //! @param provider The provider.
      //!
      void SetProvider( boost::function<T1 ()> provider ) {
         mProvider = provider;
      }

      //!
      //! Sets the name of the provider.
      //!
      //! @param name The provider name.
      //!
      void SetName( const std::string& name ) {
         mName = name;
      }

      //!
      //! Sets the provider as a singleton.
      //!
      void SetAsSingleton() {
         mProvider = boost::bind(SingletonProxy<T1>, mProvider);
      }

      //!
      //! Sets the provider as an eager singleton.
      //!
      void SetAsEagerSingleton() {
         mProvider = boost::bind(SingletonProxy<T1>, mProvider);
      }

      //!
      //! Commit the BindContext to the container.
      //!
      void Commit() {
         mContainer->AddProvider(mName, mProvider);
      }

   private :
      // Container.
      IContainerPtr mContainer;

      // Provider.
      boost::function<T1 ()> mProvider;

      // Provider name.
      std::string mName;
   };
}

#endif   // IOCPP_CONFIG_BINDCONTEXT_H
